﻿using KnifeZ.Unity.Models;
using System.Text.Json;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Web;
using System.Net.Http;

namespace KnifeZ.Unity.Helpers
{
    /// <summary>
    /// 有关HTTP请求的辅助类
    /// </summary>
    public class APIHelper
    {
        /// <summary>
        /// 默认UA
        /// </summary>
        private static readonly string DefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.52";

        /// <summary>
        /// 调用远程地址
        /// </summary>
        /// <param name="url">地址</param>
        /// <param name="method">请求方式</param>
        /// <param name="postdata">Post数据</param>
        /// <param name="timeout">超时秒数</param>
        /// <param name="proxy">代理</param>
        /// <returns>远程方法返回的内容</returns>
        public async Task<string> CallAPI(string url, HttpMethod method, IDictionary<string, string> postdata = null, int? timeout = null, WebProxy proxy = null)
        {
            try
            {
                if (string.IsNullOrEmpty(url))
                {
                    return string.Empty;
                }
                //新建http请求
                var request = WebRequest.Create(url) as HttpWebRequest;
                //如果配置了代理，则使用代理
                if (proxy != null)
                {
                    request.Proxy = proxy;
                }

                request.Method = method.ToString();
                if (postdata != null)
                {
                    if (postdata.ContainsKey("UserAgent"))
                    {
                        request.UserAgent = postdata["content-type"];
                    }
                    else
                    {
                        request.UserAgent = DefaultUserAgent;
                    }
                }
                //如果是Post请求，则设置表单
                if (method == HttpMethod.Post || method == HttpMethod.Put)
                {
                    if (postdata.ContainsKey("content-type"))
                    {
                        request.ContentType = postdata["content-type"];
                    }
                    else
                    {
                        request.ContentType = "application/x-www-form-urlencoded";
                    }
                    if (postdata == null || postdata.Count == 0)
                    {
                        request.ContentLength = 0;
                    }
                }
                //设置超时
                if (timeout.HasValue)
                {
                    request.ContinueTimeout = timeout.Value;
                }
                request.CookieContainer = new CookieContainer();
                //填充表单数据
                if (!(postdata == null || postdata.Count == 0))
                {
                    var buffer = new StringBuilder();
                    var i = 0;
                    foreach (string key in postdata.Keys)
                    {
                        if (i > 0)
                        {
                            buffer.AppendFormat("&{0}={1}", key, postdata[key]);
                        }
                        else
                        {
                            buffer.AppendFormat("{0}={1}", key, postdata[key]);
                        }
                        i++;
                    }
                    var data = Encoding.UTF8.GetBytes(buffer.ToString());
                    using (var stream = await request.GetRequestStreamAsync())
                    {
                        stream.Write(data, 0, data.Length);
                    }
                }


                var res = await request.GetResponseAsync();
                var wsp = (HttpWebResponse)res;
                Stream st = null;
                //如果远程服务器采用了gzip，增进行相应的解压缩
                if (wsp.Headers[HttpResponseHeader.ContentEncoding]?.ToLower().Contains("gzip") == true)
                {
                    st = new GZipStream(st, CompressionMode.Decompress);
                }
                else
                {
                    st = wsp.GetResponseStream();
                }
                //设置编码
                var encode = Encoding.UTF8;
                if (!string.IsNullOrEmpty(wsp.Headers[HttpResponseHeader.ContentEncoding]))
                {
                    encode = Encoding.GetEncoding(wsp.Headers[HttpResponseHeader.ContentEncoding]);
                }
                //读取内容
                var sr = new StreamReader(st, encode);
                var ss = sr.ReadToEnd();
                sr.Dispose();
                wsp.Dispose();
                return ss;
            }
            catch (Exception ex)
            {
                //返回失败信息
                SimpleListItem rv = new SimpleListItem()
                {
                    Text = ex.Message,
                    Value = ex.StackTrace
                };
                return HttpUtility.UrlDecode(JsonSerializer.Serialize(rv));
            }
        }

        /// <summary>
        /// 调用远程方法，返回强类型
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="url">地址</param>
        /// <param name="method">请求方式</param>
        /// <param name="postdata">Post数据</param>
        /// <param name="timeout">超时秒数</param>
        /// <param name="proxy">代理</param>
        /// <returns>强类型</returns>
        public async Task<T> CallAPI<T>(string url, HttpMethod method, IDictionary<string, string> postdata = null, int? timeout = null, WebProxy proxy = null)
        {
            var s = await CallAPI(url, method, postdata, timeout, proxy);
            return JsonSerializer.Deserialize<T>(s);
        }

        /// <summary>
        /// Get请求，返回强类型
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="url">地址</param>
        /// <param name="postdata">Post数据</param>
        /// <param name="timeout">超时秒数</param>
        /// <param name="proxy">代理</param>
        /// <returns>强类型</returns>
        public async Task<T> GetAsync<T>(string url, IDictionary<string, string> postdata = null, int? timeout = null, WebProxy proxy = null)
        {
            var s = await CallAPI(url, HttpMethod.Get, postdata, timeout, proxy);
            return JsonSerializer.Deserialize<T>(s);
        }
        /// <summary>
        /// Post请求，返回强类型
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="url">地址</param>
        /// <param name="postdata">Post数据</param>
        /// <param name="timeout">超时秒数</param>
        /// <param name="proxy">代理</param>
        /// <returns>强类型</returns>
        public async Task<T> PostAsync<T>(string url, IDictionary<string, string> postdata = null, int? timeout = null, WebProxy proxy = null)
        {
            var s = await CallAPI(url, HttpMethod.Post, postdata, timeout, proxy);
            return JsonSerializer.Deserialize<T>(s);
        }
        /// <summary>
        /// Get请求
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="url">地址</param>
        /// <param name="postdata">Post数据</param>
        /// <param name="timeout">超时秒数</param>
        /// <param name="proxy">代理</param>
        /// <returns>强类型</returns>
        public async Task<string> GetAsync(string url, IDictionary<string, string> postdata = null, int? timeout = null, WebProxy proxy = null)
        {
            var s = await CallAPI(url, HttpMethod.Get, postdata, timeout, proxy);
            return s;
        }
        /// <summary>
        /// Post请求
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="url">地址</param>
        /// <param name="postdata">Post数据</param>
        /// <param name="timeout">超时秒数</param>
        /// <param name="proxy">代理</param>
        /// <returns>强类型</returns>
        public async Task<string> PostAsync(string url, IDictionary<string, string> postdata = null, int? timeout = null, WebProxy proxy = null)
        {
            var s = await CallAPI(url, HttpMethod.Post, postdata, timeout, proxy);
            return s;
        }

        /// <summary>
        /// Http下载文件
        /// </summary>
        public string HttpDownloadFile(string url, string path)
        {
            // 设置参数
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            //发送请求并获取相应回应数据
            HttpWebResponse response = request.GetResponse() as HttpWebResponse;
            //直到request.GetResponse()程序才开始向目标网页发送Post请求
            Stream responseStream = response.GetResponseStream();
            //创建本地文件写入流
            Stream stream = new FileStream(path, FileMode.Create);
            byte[] bArr = new byte[1024];
            int size = responseStream.Read(bArr, 0, (int)bArr.Length);
            while (size > 0)
            {
                stream.Write(bArr, 0, size);
                size = responseStream.Read(bArr, 0, (int)bArr.Length);
            }
            stream.Close();
            responseStream.Close();
            return path;
        }


        /// <summary>
        /// 上传附件到服务器
        /// </summary>
        /// <param name="filePath">文件本地路径(绝对路径)</param>
        /// <param name="url">远程接口</param>
        /// <param name="headerCollection"></param>
        /// <returns></returns>
        public string FileTransfer(string filePath, string url, WebHeaderCollection headerCollection)
        {
            //判断本地是否存在该文件
            if (File.Exists(filePath))
            {
                FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                BinaryReader r = new BinaryReader(fs);
                string strBoundary = "----------" + DateTime.Now.Ticks.ToString("x");
                byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + strBoundary + "\r\n");
                StringBuilder sb = new StringBuilder();
                sb.Append("--");
                sb.Append(strBoundary);
                sb.Append("\r\n");
                sb.Append("Content-Disposition: form-data; name=\"");
                sb.Append("file");
                sb.Append("\"; filename=\"");
                sb.Append("/" + filePath);
                sb.Append("\";");
                sb.Append("\r\n");
                sb.Append("Content-Type: ");
                sb.Append("application/octet-stream");
                sb.Append("\r\n");
                sb.Append("\r\n");
                string strPostHeader = sb.ToString();
                byte[] postHeaderBytes = Encoding.UTF8.GetBytes(strPostHeader);     // 根据uri创建HttpWebRequest对象   
                HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(url));
                httpReq.Method = "POST";
                //对发送的数据不使用缓存   
                httpReq.AllowWriteStreamBuffering = false;
                //设置获得响应的超时时间（300秒）   
                httpReq.Timeout = 300000;
                httpReq.Headers.Clear();
                httpReq.Headers = headerCollection;
                httpReq.UserAgent = DefaultUserAgent;
                httpReq.ContentType = "multipart/form-data; boundary=" + strBoundary;
                long length = fs.Length + postHeaderBytes.Length + boundaryBytes.Length;
                httpReq.ContentLength = length;
                try
                {
                    //每次上传4k  
                    int bufferLength = 409600;
                    byte[] buffer = new byte[bufferLength];
                    //已上传的字节数   
                    long offset = 0;
                    //开始上传时间   
                    DateTime startTime = DateTime.Now;
                    int size = r.Read(buffer, 0, bufferLength);
                    Stream postStream = httpReq.GetRequestStream();
                    //发送请求头部消息   
                    postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
                    while (size > 0)
                    {
                        postStream.Write(buffer, 0, size);
                        offset += size;
                        TimeSpan span = DateTime.Now - startTime;
                        double second = span.TotalSeconds;
                        size = r.Read(buffer, 0, bufferLength);
                    }
                    //添加尾部的时间戳   
                    postStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                    postStream.Close();
                    //获取服务器端的响应   
                    WebResponse webRespon = httpReq.GetResponse();
                    Stream s = webRespon.GetResponseStream();
                    //读取服务器端返回的消息  
                    StreamReader sr = new StreamReader(s);
                    String sReturnString = sr.ReadLine();
                    s.Close();
                    sr.Close();
                    return sReturnString;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    fs.Close();
                    r.Close();
                }
            }
            return "Error：文件不存在！";
        }
    }
}
